﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Model;
using System.Data.Objects.DataClasses;
using System.Data.Objects;
using System.Data;

namespace CBE.Model
{
    public class GenericEntityManagerDataAccess<E, C, EV, DC> : AbstractEntityDataAccess<DC>, IGenericEntityManagerDataAccess<E, C, EV>
        where E : EntityObject, new()
        where C : CriteriaEntity
        where EV : ViewEntity
        where DC : ObjectContext, new()
    {
        List<String> _relatedEntitySets = new List<string>();
        public List<String> RelatedEntitySets
        {
            get { return _relatedEntitySets; }
            set { _relatedEntitySets = value; } 
        }

        #region IGenericDataAccess<E,C,EV> Members

        public virtual E Read(Guid id)
        {
            var entityobject = this.ReadEntity(id);
            if (entityobject.EntityState != System.Data.EntityState.Unchanged)
            {
                ObjectContext.Refresh(RefreshMode.StoreWins, entityobject);
            }
            return entityobject;
        }

        protected virtual E ReadEntity(Guid id)
        {
            throw new NotImplementedException();
        }

        public virtual List<EV> Read(C criteria)
        {
            throw new NotImplementedException();
        }


        protected void DeleteRelatedEntities()
        {
            foreach (var item in RelatedEntitySets)
            {
                var deletedRelationships = ObjectContext.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Deleted).
                    Where(obj => obj.IsRelationship && obj.EntitySet.Name.Contains(item));

                if (deletedRelationships.Count() != 0)
                {
                    foreach (var relation in deletedRelationships)
                    {
                        var entityKey = relation.OriginalValues[1];
                        var entity = ObjectContext.GetObjectByKey(entityKey as EntityKey);
                        ObjectContext.DeleteObject(entity);
                    }
                }
            }
        }

        public virtual void Save(E entity)
        {
            if (entity.EntityKey == null || entity.EntityState == System.Data.EntityState.Added)
            {
                ObjectContext.AddObject(this.GetEntitySet(entity), entity);
            }
            else if (entity.EntityState == System.Data.EntityState.Detached)
            {
                ObjectContext.Attach(entity);
            }

            this.DeleteRelatedEntities();

            ObjectContext.SaveChanges();

            this.AfterSave(entity);
        }

        protected virtual void AfterSave(E entity)
        {
        }

        private string GetEntitySet(E entity)
        {
            return entity.GetType().Name;
        }

        public void Delete(ViewEntity viewEntity)
        {
            var entityObject = this.Read(viewEntity.ID);
            ObjectContext.DeleteObject(entityObject);
            ObjectContext.SaveChanges();
        }

        public virtual List<E> ReadEntities()
        {
            var list = ObjectContext.CreateQuery<E>(GetEntitySet(new E())).ToList();
            return list;
        }

        public virtual List<E> ReadEntitiesByParameter(EntityObject entityObject)
        {
            var list = ObjectContext.CreateQuery<E>(GetEntitySet(new E())).ToList();
            return list;
        }

        #endregion

        #region IGenericEntityManagerDataAccess<E,C,EV> Members


        public void RejectChanges()
        {
            base.RejectChanges();
        }

        #endregion

    }
}